// 客户端文件
import * as net from 'net';
import * as readline from 'readline';
import * as util from './util';

enum SupportCommand {
    LOGIN = "login",
    LOGOUT = "logout",
    SAY = "say",
    LIST = "ls",
    EXIT = "exit",
    HELP = "help",
    WHISPER = "whisper",
}

interface CommandAttribute {
    command: SupportCommand;
    description: string;
    example: string;
}

type ConsoleCommandType = {
    [key: string]: CommandAttribute;
};

const ConsoleCommand: ConsoleCommandType = {
    LOGIN: {
        command: SupportCommand.LOGIN,
        description: "登录聊天室",
        example: "/login <IP> <PORT> <用户名>"
    },
    LIST: {
        command: SupportCommand.LIST,
        description: "查看当前在线用户",
        example: "/ls"
    },
    SAY: {
        command: SupportCommand.SAY,
        description: "发送消息",
        example: "[/say] <消息>"
    },
    WHISPER: {
        command: SupportCommand.WHISPER,
        description: "悄悄话",
        example: "/whisper <用户名> <消息>"
    },
    LOGOUT: {
        command: SupportCommand.LOGOUT,
        description: "退出登录",
        example: "/logout"
    },
    EXIT: {
        command: SupportCommand.EXIT,
        description: "退出聊天室程序",
        example: "/exit"
    },
    HELP: {
        command: SupportCommand.HELP,
        description: "查看帮助信息",
        example: "/help"
    },
}

const userList: util.UserInfo[] = []
let server: net.Socket | null = null;
let name: string | null = null;
let isLogin: boolean = false
const LOGOUT_MESSAGE = JSON.stringify({ command: util.RequestCommand.LOGOUT, data: null });

function clearServer() {
    server = null;
    name = null;
    isLogin = false;
    userList.length = 0;
}

async function handleLoginCommand(args: string[]) {
    // 验证
    if (args.length < 3) {
        util.logInConsole('参数错误，请输入 /login <IP> <PORT> <用户名>');
        return;
    }

    const ip = args[0];
    const port = parseInt(args[1]);
    if (isNaN(port)) {
        util.logInConsole('端口必须是数字');
        return;
    }
    if (port < 0 || port > 65535) {
        util.logInConsole('端口必须在0到65535之间');
        return;
    }
    const username = args[2].trim();
    if (!username) {
        util.logInConsole('用户名不能为空');
        return;
    }

    if (server && isLogin) {
        // 退出当前聊天室
        handleLogoutCommand();
    }

    // 建立连接
    server = new net.Socket();
    server.connect(port, ip, () => {
        name = username;
        if (server === null) {
            return;
        }
        server.sendJSON(util.RequestCommand.LOGIN, username)
    })

    server.on('data', (dataBuffer) => {
        const dataString = dataBuffer.toString();
        let data: util.ResponseMessage<any>;

        try {
            data = JSON.parse(dataString);
        } catch (error) {
            return;
        }
        switch (data.command) {
            case util.ResponseCommand.INVALID_COMMAND:
                util.logInConsole('当前版本暂不支持此命令');
                break;
            case util.ResponseCommand.REMAIN_USER:
                util.logInConsole('欢迎加入聊天室！');
                let users: util.UserInfo[] = data.data;
                userList.push(...users);
                isLogin = true;
                handleListCommand();
                break;
            case util.ResponseCommand.NEW_USER:
                let newUser: util.UserInfo = data.data;
                userList.push(newUser);
                util.logInConsole(`用户 ${newUser.name}(${newUser.ip}) 已上线`);
                break;
            case util.ResponseCommand.INVALID_USERNAME:
                util.logInConsole('无效用户名');
                break;
            case util.ResponseCommand.USERNAME_EXIST:
                util.logInConsole('用户名已存在');
                break;
            case util.ResponseCommand.USER_LOGGED_IN:
                util.logInConsole('用户已登录');
                break;
            case util.ResponseCommand.LOGOUT_USER:
                let logoutUserId: string = data.data;
                let logoutUser: util.UserInfo | null = null;
                for (let i = 0; i < userList.length; i++) {
                    if (userList[i].id === logoutUserId) {
                        logoutUser = userList[i];
                        userList.splice(i, 1);
                        break;
                    }
                }
                if (logoutUser) {
                    util.logInConsole(`用户 ${logoutUser.name}(${logoutUser.ip}) 已下线`);
                }
                break;
            case util.ResponseCommand.USER_CHAT:
                {
                    let userChat: util.UserChat = data.data;
                    let user: util.UserInfo = userList.find(user => user.id === userChat.id) as util.UserInfo;
                    if (user) {
                        console.log(`${user.name}: ${userChat.message}`);
                    }
                }
                break;
            case util.ResponseCommand.SERVER_CLOSE:
                util.logInConsole('服务器已关闭');
                clearServer()
                break;
            case util.ResponseCommand.USER_NOT_LOGIN:
                util.logInConsole('用户未登录');
                break;
            case util.ResponseCommand.USER_WHISPER:
                {
                    let userWhisper: util.whisperMessage = data.data;
                    let user: util.UserInfo = userList.find(user => user.id === userWhisper.id) as util.UserInfo;
                    if (user) {
                        console.log(`${user.name}悄悄对你说: ${userWhisper.message}`);
                    }
                }
                break;
            case util.ResponseCommand.USER_NOT_EXIST:
                util.logInConsole('当前用户尚未登录');
                break;
            default:
                let unknownCommand: never = data.command;
                break;
        }

    })

    server.on('error', e => {
        try {
            if ("code" in e) {
                let error: typeof e | { code: string } = e;
                if (error.code === "ECONNRESET") {
                    util.logInConsole('服务器连接关闭')
                } else {
                    util.logInConsole(`服务器连接错误`)
                }
            }
        } finally {
            clearServer()
        }
    });
}

function handleLogoutCommand() {
    try {
        if (server) {
            if (isLogin) {
                server.write(LOGOUT_MESSAGE)
            }
            util.logInConsole('已退出聊天室');
        } else {
            util.logInConsole('当前未连接到聊天室');
        }
    } catch (_) {
    } finally {
        clearServer()
    }
}

function handleSayCommand(message: string) {
    // 验证message
    if (!message) {
        util.logInConsole('消息不能为空');
        return;
    }
    // 验证server
    if (server === null || !isLogin) {
        util.logInConsole('当前未连接到聊天室');
        return;
    }
    // 发送消息
    server.sendJSON(util.RequestCommand.SAY, message)
}

function handleListCommand() {
    if (server === null || !isLogin) {
        util.logInConsole('当前未连接到聊天室');
        return;
    }
    if (userList.length === 0) {
        util.logInConsole('当前无人在线');
    } else {
        util.logInConsole('当前用户列表:');
        console.table(userList.map(user => {
            return {
                name: user.name,
                id: user.id,
                ip: user.ip
            }
        }))
        util.logInConsole(`共 ${userList.length} 人在线`);
    }
}

function handleHelpCommand() {
    util.logInConsole('当前系统可用命令如下:');
    console.table(ConsoleCommand);
}

function handleExitCommand() {
    handleLogoutCommand()
    process.exit(0)
}

function handleWhisperCommand(args: string[]) {
    if (!server || !isLogin) {
        util.logInConsole('当前未连接到聊天室');
        return
    }
    if (args.length < 2) {
        util.logInConsole('请输入正确的消息格式: /whisper 用户名 消息内容');
        return;
    }
    let userName = args.shift();
    let message = args.join(' ');
    if (!userName || !message) {
        util.logInConsole('请输入正确的消息格式: /whisper 用户名 消息内容');
        return;
    }
    // 获取用户
    let user = userList.find(user => user.name === userName);
    if (!user) {
        util.logInConsole('用户未加入房间');
        return;
    }
    // 发送消息
    let data: util.whisperMessage = {
        id: user.id,
        message: message
    }
    server.sendJSON(util.RequestCommand.WHISPER, data)
}

function parseCommand(input: string) {
    // 判断是不是命令
    if (input.startsWith('/')) {
        // 获取/后面的字符
        const command = input.substring(1);
        // 根据空格分隔
        const args = command.split(' ');
        // 获取命令名称
        const commandName: SupportCommand = args.shift()?.toLowerCase() as SupportCommand;

        // 根据命令名称执行不同的操作
        switch (commandName) {
            case SupportCommand.LOGIN:
                handleLoginCommand(args);
                break;
            case SupportCommand.LOGOUT:
                handleLogoutCommand();
                break;
            case SupportCommand.SAY:
                const message = input.substring(("/" + SupportCommand.SAY + " ").length);
                handleSayCommand(message.trim());
                break;
            case SupportCommand.LIST:
                handleListCommand();
                break;
            case SupportCommand.HELP:
                handleHelpCommand();
                break;
            case SupportCommand.EXIT:
                handleExitCommand();
                break;
            case SupportCommand.WHISPER:
                handleWhisperCommand(args);
                break;
            default:
                let unknownCommand: never = commandName;
                util.logInConsole('未知命令');
        }
    } else {
        handleSayCommand(input)
    }
}

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

util.logInConsole('欢迎使用聊天室客户端，请输入 /help 查看可用命令');
rl.on('line', (input) => {
    if (input.trim()) {
        parseCommand(input.trim());
    }
});